package com.wsq.ui;

import java.text.ParseException;

import org.javia.arity.SyntaxException;

import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
import android.view.animation.TranslateAnimation;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ViewSwitcher;

import com.wsq.calculate.Calculate;
import com.wsq.function.CalculateSimpleEngine;
import com.wsq.function.CalculatorEditable;
import com.wsq.function.DisplayLogic;
import com.wsq.function.DisplayLogic.SimpleLogic;

public class CalculateDisplay extends ViewSwitcher {

	private TranslateAnimation inAnimationUp;
	private TranslateAnimation outAnimationUp;
	private TranslateAnimation inAnimationDown;
	private TranslateAnimation outAnimationDown;

	public enum Scroll {
		UP, DOWN, NONE
	}

	private static final int ANIM_DURATION = 500;

	private static final char[] ACCEPTED_CHARS = "0123456789.+-*/\u2212\u00d7\u00f7()!%^"
			.toCharArray();

	private DisplayLogic mLogic;
	public SimpleLogic mSimpleLogic;
	private boolean mComputeLinelength;

	public CalculateDisplay(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onFinishInflate() {
		// TODO Auto-generated method stub
		super.onFinishInflate();
		Calculate calculate = (Calculate) getContext();
		calculate.adjustFontSize((TextView) getChildAt(0));
		calculate.adjustFontSize((TextView) getChildAt(1));
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		// TODO Auto-generated method stub
		super.onLayout(changed, left, top, right, bottom);
		if (!mComputeLinelength && mLogic != null) {
			int maxLength=getLinelength((TextView) getCurrentView());
			mLogic.setLinelength(maxLength);
			setFilters(maxLength);
			mComputeLinelength = true;
		}
	}

	private int getLinelength(TextView showText) {
		int available = showText.getWidth() - showText.getTotalPaddingLeft()
				- showText.getTotalPaddingRight();
		Paint paint = showText.getPaint();
		float digitWidth = paint.measureText("01234567899876543210") / 20f;
		return (int) (available / digitWidth);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
		inAnimationUp = new TranslateAnimation(0, 0, h, 0);
		inAnimationUp.setDuration(ANIM_DURATION);
		outAnimationUp = new TranslateAnimation(0, 0, 0, -h);
		outAnimationUp.setDuration(ANIM_DURATION);
		inAnimationDown = new TranslateAnimation(0, 0, -h, 0);
		inAnimationDown.setDuration(ANIM_DURATION);
		outAnimationDown = new TranslateAnimation(0, 0, 0, h);
		outAnimationDown.setDuration(ANIM_DURATION);
	}

	public void setLogic(DisplayLogic logic) {
		this.mLogic = logic;
		this.mSimpleLogic = mLogic.mSimpleLogic;
		NumberKeyListener numberKeyListener = new NumberKeyListener() {

			@Override
			public int getInputType() {
				// TODO Auto-generated method stub
				return InputType.TYPE_NULL;
			}

			// Only fiter char.
			@Override
			protected char[] getAcceptedChars() {
				// TODO Auto-generated method stub
				return ACCEPTED_CHARS;
			}

			public CharSequence filter(CharSequence source, int start, int end,
					Spanned dest, int dstart, int dend) {
				/*
				 * the EditText should still accept letters (eg. 'sin') coming
				 * from the on-screen touch buttons, so don't filter anything.
				 */
				return null;
			}

		};

		Editable.Factory factory = new CalculatorEditable.Factory(logic);
		for (int i = 0; i < 2; i++) {
			EditText text = (EditText) getChildAt(i);
			text.setBackgroundDrawable(null);
			if (mLogic.isKeepExpress()) {
				text.setEditableFactory(factory);
			} else {
				text.setCursorVisible(mLogic.isKeepExpress());
			}
			text.setKeyListener(numberKeyListener);
		}
	}

	public void setFilters(int length) {
		for (int i = 0; i < 2; i++) {
			EditText text = (EditText) getChildAt(i);
			text.setFilters(new InputFilter[] { new InputFilter.LengthFilter(
					length) });
		}
	}

	public void delete() {
		EditText editor = (EditText) getCurrentView();
		int length = editor.length();
		if (length != 0)
			editor.getText().delete(length - 1, length);
	}

	public void insert(String delta) {
		EditText editor = (EditText) getCurrentView();
		int cursor = editor.getSelectionStart();
		// convenience for replace(int, int, CharSequence, int, int)
		editor.getText().insert(cursor, delta);
	}

	public void append(String delta) {
		EditText editor = (EditText) getCurrentView();
		editor.getText().append(delta);
	}

	public void handle(String delta) throws ParseException, SyntaxException,
			NumberFormatException {
		// if (mLogic.filterFirstChar(delta)) {
		// return;
		// }

		if (mLogic.shouldClear(delta)) {
			setText(delta);
			mSimpleLogic.lastIsOperator = false;
			// mSimpleLogic.resetOperand();
			return;
		}

		String currentShowString = getText().toString();

		if ("e".equals(delta) && currentShowString.contains("e")) {
			return;
		}
		
		if (".".equals(delta) && currentShowString.contains(".")) {
			return;
		}

		if (mSimpleLogic.isValidOperator(delta)) {// 合法操作符
			if (mSimpleLogic.lastIsOperator) {
				mSimpleLogic.resetOperator(delta);
			} else {
				mSimpleLogic.addOperand(currentShowString);
				if (mSimpleLogic.canCalculate()) {
					String result = mSimpleLogic.calculate();
					mSimpleLogic.afterCalculate(result, delta);
					setText(result);
					mLogic.setResult(result);
				} else {
					mSimpleLogic.addOperator(delta);
				}
			}

		} else if ("=".equals(delta)) {// '='

			if (mSimpleLogic.canCalculateEqual(currentShowString)) {
				mSimpleLogic.addOperand(currentShowString);
				String result = mSimpleLogic.calculateForEqual();
				mSimpleLogic.setEqualSuffix();
				mSimpleLogic.clearCalculate();
				setText(result);
				mLogic.setResult(result);
			} else {
				if (mSimpleLogic.equalSuffix != null) {
					currentShowString = mSimpleLogic
							.calculateWithEqualSuffix(currentShowString);
					setText(currentShowString);
					mLogic.setResult(currentShowString);
				}
			}
			mSimpleLogic.lastIsOperator = false;
		} else if ((delta.length() == 1 && Character.isDigit(delta.charAt(0)))
				|| "e".equals(delta) || ".".equals(delta)) { // 合法操作数
			if ("0".equals(currentShowString)) {
				if (delta.equals(".")) {
					append(delta);
				} else {
					setText(delta);
				}
			} else {
				if (mSimpleLogic.lastIsOperator) {
					setText(delta);
				} else {
					append(delta);
				}
			}

			mSimpleLogic.lastIsOperator = false;

		} else { // 其他
			mSimpleLogic.lastIsOperator = false;
			if ("±".equals(delta)) {
				if (currentShowString.contains("e-")) {
					setText(currentShowString.replace("e-", "e"));
				} else if (currentShowString.contains("e")) {
					setText(currentShowString.replace("e", "e-"));
				} else if (currentShowString.startsWith("-")) {
					setText(currentShowString.replace("-", ""));
				} else {
					setText(currentShowString = "-" + currentShowString);
				}
				return;
			}
			currentShowString = mSimpleLogic.translateInput2Result(delta,
					currentShowString);
			setText(currentShowString);
			mLogic.setResult(currentShowString);
		}
	}

	public void setText(String delta) {
		EditText editor = (EditText) getCurrentView();
		editor.setText(delta);
	}

	public EditText getEditText() {
		return (EditText) getCurrentView();
	}

	public Editable getText() {
		EditText text = (EditText) getCurrentView();
		return text.getText();
	}

	public void setText(CharSequence text, Scroll dir) {
		if (getText().length() == 0) {
			dir = Scroll.NONE;
		}

		if (dir == Scroll.UP) {
			setInAnimation(inAnimationUp);
			setOutAnimation(outAnimationUp);
		} else if (dir == Scroll.DOWN) {
			setInAnimation(inAnimationDown);
			setOutAnimation(outAnimationDown);
		} else { // Scroll.NONE
			setInAnimation(null);
			setOutAnimation(null);
		}

		EditText editText = (EditText) getNextView();
		editText.setText(text);
		// Calculator.log("selection to " + text.length() + "; " + text);
		editText.setSelection(text.length());
		showNext();
	}

	public void setSelection(int i) {
		EditText text = (EditText) getCurrentView();
		text.setSelection(i);
	}

	public int getSelectionStart() {
		EditText text = (EditText) getCurrentView();
		return text.getSelectionStart();
	}

	@Override
	public void setOnKeyListener(OnKeyListener l) {
		// TODO Auto-generated method stub
		getChildAt(0).setOnKeyListener(l);
		getChildAt(1).setOnKeyListener(l);
	}

	@Override
	protected void onFocusChanged(boolean gainFocus, int direction,
			Rect previouslyFocusedRect) {
		// TODO Auto-generated method stub
		if (!gainFocus) {
			requestFocus();
		}
	}

}
